home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Software Money Savers / VirtualDub / Source / VirtualDub-1.7.7-src.7z / src / Asuka / source / fontextract.cpp next >
Encoding:
C/C++ Source or Header  |  2007-01-08  |  9.1 KB  |  333 lines

  1. //    Asuka - VirtualDub Build/Post-Mortem Utility
  2. //    Copyright (C) 2005-2007 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include "stdafx.h"
  19.  
  20. #define WINVER 0x0500
  21. #define _WIN32_WINNT 0x0500
  22. #include <vd2/system/memory.h>
  23. #include <vd2/system/vectors.h>
  24. #include <vd2/system/vdstl.h>
  25. #include <vd2/system/filesys.h>
  26. #include <vd2/system/math.h>
  27. #include <vd2/Kasumi/pixmaputils.h>
  28. #include <vector>
  29. #include <algorithm>
  30. #include <windows.h>
  31.  
  32. void VDNORETURN help_fontextract() {
  33.     printf("usage: fontextract <.ttf file> <font name> <start char> <end char> <output file> <symbol prefix>\n");
  34.     exit(5);
  35. }
  36.  
  37. namespace {
  38.     struct GlyphInfo {
  39.         ABCFLOAT mWidths;
  40.         int mPointStart;
  41.         int mCommandStart;
  42.  
  43.         GlyphInfo()
  44.             : mPointStart(0)
  45.             , mCommandStart(0)
  46.         {
  47.             mWidths.abcfA = 0;
  48.             mWidths.abcfB = 0;
  49.             mWidths.abcfC = 0;
  50.         }
  51.     };
  52. }
  53.  
  54. void tool_fontextract(const vdfastvector<const char *>& args, const vdfastvector<const char *>& switches) {
  55.     if (args.size() < 6)
  56.         help_fontextract();
  57.  
  58.     printf("Asuka: Extracting font: %s -> %s.\n", args[0], args[4]);
  59.     
  60.     int startChar;
  61.     int endChar;
  62.  
  63.     if (1 != sscanf(args[2], "%d", &startChar) || 1 != sscanf(args[3], "%d", &endChar))
  64.         help_fontextract();
  65.  
  66.     if (startChar < 0 || endChar > 0xFFFF || endChar <= startChar) {
  67.         printf("Asuka: Invalid character range %d-%d\n", startChar, endChar);
  68.         exit(10);
  69.     }
  70.  
  71.     int fontsAdded = AddFontResourceEx(args[0], FR_NOT_ENUM | FR_PRIVATE, 0);
  72.  
  73.     if (!fontsAdded) {
  74.         printf("Asuka: Unable to load font file: %s\n", args[0]);
  75.         exit(10);
  76.     }
  77.  
  78.     HFONT hfont = CreateFontA(10, 0, 0, 0, 0, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, args[1]);
  79.     if (!hfont) {
  80.         printf("Asuka: Unable to instantiate font: %s\n", args[1]);
  81.         exit(10);
  82.     }
  83.  
  84.     HDC hdc = CreateDC("DISPLAY", 0, 0, 0);
  85.     HGDIOBJ hfontOld = SelectObject(hdc, hfont);
  86.     MAT2 m = { {0,1},{0,0},{0,0},{0,1} };
  87.  
  88.     union {
  89.         OUTLINETEXTMETRICW m;
  90.         char buf[2048];
  91.     } metrics;
  92.  
  93.     if (!GetOutlineTextMetricsW(hdc, sizeof metrics, &metrics.m)) {
  94.         printf("Asuka: Unable to retrieve outline text metrics.\n");
  95.         exit(10);
  96.     }
  97.  
  98.     SelectObject(hdc, hfontOld);
  99.     DeleteObject(hfont);
  100.     
  101.     hfont = CreateFontA(metrics.m.otmEMSquare, 0, 0, 0, 0, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, args[1]);
  102.     if (!hfont) {
  103.         printf("Asuka: Unable to instantiate font: %s\n", args[1]);
  104.         exit(10);
  105.     }
  106.  
  107.     hfontOld = SelectObject(hdc, hfont);
  108.  
  109.     if (!GetOutlineTextMetricsW(hdc, sizeof metrics, &metrics.m)) {
  110.         printf("Asuka: Unable to retrieve outline text metrics.\n");
  111.         exit(10);
  112.     }
  113.  
  114.     FILE *f = fopen(args[4], "w");
  115.     if (!f) {
  116.         printf("Asuka: Unable to open output file: %s\n", args[4]);
  117.         exit(10);
  118.     }
  119.  
  120.     std::vector<GlyphInfo> glyphs(endChar - startChar + 1);
  121.  
  122.     sint32 minX = 0x7FFFFFFF;
  123.     sint32 minY = 0x7FFFFFFF;
  124.     sint32 maxX = -0x7FFFFFFF - 1;
  125.     sint32 maxY = -0x7FFFFFFF - 1;
  126.  
  127.     vdfastvector<sint32> points;
  128.     vdfastvector<uint8> commands;
  129.  
  130.     for(int c=startChar; c<endChar; ++c) {
  131.         GlyphInfo& info = glyphs[c - startChar];
  132.         info.mPointStart = points.size() >> 1;
  133.         info.mCommandStart = commands.size();
  134.  
  135.         GetCharABCWidthsFloatW(hdc, c, c, &info.mWidths);
  136.  
  137.         // encode glyph outline
  138.         GLYPHMETRICS gm;
  139.  
  140.         if (GDI_ERROR == GetGlyphOutlineW(hdc, c, GGO_METRICS, &gm, 0, NULL, &m)) {
  141.             printf("Asuka: Unable to obtain glyph metrics for char %d.\n", c);
  142.             exit(20);
  143.         }
  144.  
  145.         DWORD dwBytes = GetGlyphOutlineW(hdc, c, GGO_NATIVE | GGO_UNHINTED, &gm, 0, NULL, &m);
  146.         if (dwBytes == 0xFFFFFFFF) {
  147.             printf("Asuka: Unable to obtain glyph outline for char %d.\n", c);
  148.             exit(20);
  149.         }
  150.  
  151.         // GetGlyphOutline() doesn't like providing results for spaces.
  152.         if (gm.gmBlackBoxX <= 0 || gm.gmBlackBoxY <= 0)
  153.             continue;
  154.  
  155.         void *buf = malloc(dwBytes);
  156.         GetGlyphOutlineW(hdc, c, GGO_NATIVE | GGO_UNHINTED, &gm, dwBytes, buf, &m);
  157.  
  158.         void *limit = (char *)buf + dwBytes;
  159.         TTPOLYGONHEADER *pHdr = (TTPOLYGONHEADER *)buf;
  160.  
  161.         sint32 lastCode = 0;
  162.  
  163.         while(pHdr != limit) {
  164.             VDASSERT(pHdr->dwType == TT_POLYGON_TYPE);
  165.  
  166.             sint32 x = *(const sint32 *)&pHdr->pfxStart.x;
  167.             sint32 y = *(const sint32 *)&pHdr->pfxStart.y;
  168.  
  169.             if (minX > x)
  170.                 minX = x;
  171.             if (minY > y)
  172.                 minY = y;
  173.             if (maxX < x)
  174.                 maxX = x;
  175.             if (maxY < y)
  176.                 maxY = y;
  177.  
  178.             points.push_back(x);
  179.             points.push_back(y);
  180.  
  181.             TTPOLYCURVE *pCurve = (TTPOLYCURVE *)(pHdr + 1);
  182.             TTPOLYCURVE *pCurveEnd = (TTPOLYCURVE *)((char *)pHdr + pHdr->cb);
  183.  
  184.             while(pCurve != pCurveEnd) {
  185.                 VDASSERT(pCurve->wType == TT_PRIM_QSPLINE || pCurve->wType == TT_PRIM_LINE);
  186.  
  187.                 POINTFX *ppfx = pCurve->apfx;
  188.  
  189.                 for(int i=0; i<pCurve->cpfx; ++i) {
  190.                     sint32 x = *(const sint32 *)&ppfx->x;
  191.                     sint32 y = *(const sint32 *)&ppfx->y;
  192.  
  193.                     if (minX > x)
  194.                         minX = x;
  195.                     if (minY > y)
  196.                         minY = y;
  197.                     if (maxX < x)
  198.                         maxX = x;
  199.                     if (maxY < y)
  200.                         maxY = y;
  201.  
  202.                     points.push_back(x);
  203.                     points.push_back(y);
  204.                     ++ppfx;
  205.                 }
  206.  
  207.                 if (pCurve->wType == TT_PRIM_LINE) {
  208.                     if ((lastCode & 3) != 2) {
  209.                         if (lastCode)
  210.                             commands.push_back(lastCode);
  211.  
  212.                         lastCode = 2 - 4;
  213.                     }
  214.  
  215.                     for(int i=0; i<pCurve->cpfx; ++i) {
  216.                         if (lastCode >= 0x7C) {
  217.                             commands.push_back(lastCode);
  218.                             lastCode = 2 - 4;
  219.                         }
  220.  
  221.                         lastCode += 4;
  222.                     }
  223.                 } else {
  224.                     VDASSERT(pCurve->wType == TT_PRIM_QSPLINE);
  225.                     VDASSERT(!(pCurve->cpfx % 2));
  226.  
  227.                     if ((lastCode & 3) != 3) {
  228.                         if (lastCode)
  229.                             commands.push_back(lastCode);
  230.  
  231.                         lastCode = 3 - 4;
  232.                     }
  233.  
  234.                     for(int i=0; i<pCurve->cpfx; i+=2) {
  235.                         if (lastCode >= 0x7C) {
  236.                             commands.push_back(lastCode);
  237.                             lastCode = 3 - 4;
  238.                         }
  239.  
  240.                         lastCode += 4;
  241.                     }
  242.                 }
  243.  
  244.                 pCurve = (TTPOLYCURVE *)ppfx;
  245.             }
  246.  
  247.             if (lastCode) {
  248.                 commands.push_back(lastCode | 0x80);
  249.                 lastCode = 0;
  250.             }
  251.  
  252.             vdptrstep(pHdr, pHdr->cb);
  253.         }
  254.  
  255.         free(buf);
  256.     }
  257.  
  258.     GlyphInfo& lastInfo = glyphs.back();
  259.  
  260.     lastInfo.mPointStart = points.size() >> 1;
  261.     lastInfo.mCommandStart = commands.size();
  262.  
  263.     // write points
  264.     fprintf(f, "// Created by Asuka from %s.  DO NOT EDIT!\n\n", VDFileSplitPath(args[0]));
  265.     fprintf(f, "const uint16 %s_FontPointArray[]={\n", args[5]);
  266.  
  267.     float scaleX = (maxX > minX) ? 1.0f / (maxX - minX) : 0.0f;
  268.     float scaleY = (maxY > minY) ? 1.0f / (maxY - minY) : 0.0f;
  269.  
  270.     int pointElementCount = points.size();
  271.  
  272.     for(int i=0; i<pointElementCount; i+=2) {
  273.         uint8 x = VDClampedRoundFixedToUint8Fast((float)(points[i+0] - minX) * scaleX);
  274.         uint8 y = VDClampedRoundFixedToUint8Fast((float)(points[i+1] - minY) * scaleY);
  275.         uint16 pt = ((uint16)y << 8) + x;
  276.  
  277.         fprintf(f, "0x%04x,", pt);
  278.  
  279.         if ((i & 30) == 30)
  280.             putc('\n', f);
  281.     }
  282.  
  283.     if (pointElementCount & 30)
  284.         putc('\n', f);
  285.  
  286.     fprintf(f, "};\n\n");
  287.  
  288.     // write commands
  289.     fprintf(f, "const uint8 %s_FontCommandArray[]={\n", args[5]);
  290.  
  291.     int commandElementCount = commands.size();
  292.  
  293.     for(int i=0; i<commandElementCount; ++i) {
  294.         fprintf(f, "0x%02x,", commands[i]);
  295.  
  296.         if ((i & 15) == 15)
  297.             putc('\n', f);
  298.     }
  299.  
  300.     if (commandElementCount & 15)
  301.         putc('\n', f);
  302.  
  303.     fprintf(f, "};\n\n");
  304.  
  305.     // glyph data structures
  306.     fprintf(f, "const VDOutlineFontGlyphInfo %s_FontGlyphArray[]={\n", args[5]);
  307.     for(int i=startChar; i<=endChar; ++i) {
  308.         const GlyphInfo& info = glyphs[i - startChar];
  309.         fprintf(f, "{ %d, %d, %d, %d, %d },\n", info.mPointStart, info.mCommandStart, VDRoundToInt(info.mWidths.abcfA), VDRoundToInt(info.mWidths.abcfB), VDRoundToInt(info.mWidths.abcfC));
  310.     }
  311.     fprintf(f, "};\n\n");
  312.  
  313.     // top-level data structure
  314.     fprintf(f, "const VDOutlineFontInfo %s_FontInfo={\n", args[5]);
  315.     fprintf(f, "\t%s_FontPointArray,\n", args[5]);
  316.     fprintf(f, "\t%s_FontCommandArray,\n", args[5]);
  317.     fprintf(f, "\t%s_FontGlyphArray,\n", args[5]);
  318.     fprintf(f, "\t%d, %d,\n", startChar, endChar);
  319.     fprintf(f, "\t%d, %d, %d, %d,\t// bounds (16:16)\n", minX, minY, maxX, maxY);
  320.     fprintf(f, "\t%d,\t// em square\n", metrics.m.otmEMSquare);
  321.     fprintf(f, "\t%d,\t// ascent\n", metrics.m.otmAscent);
  322.     fprintf(f, "\t%d,\t// descent\n", metrics.m.otmDescent);
  323.     fprintf(f, "\t%d,\t// line gap\n", metrics.m.otmLineGap);
  324.     fprintf(f, "};\n");
  325.  
  326.     printf("Asuka: %d point bytes, %d command bytes, %d glyph info bytes.\n", (int)points.size(), (int)commands.size(), (endChar - startChar + 1) * 10);
  327.  
  328.     SelectObject(hdc, hfontOld);
  329.     DeleteDC(hdc);
  330.  
  331.     DeleteObject(hfont);
  332. }
  333.